// Support functions for all blitters
// rearranged by regret
#include "burner.h"
#include "vid_support.h"

VidSupport vidSupport;

VidSupport::VidSupport()
{
	image = 0;
	width = height = 0;
	pitch = 0;
	rotate = 0;
	aspect = (double)4 / (double)3;
}

VidSupport::~VidSupport()
{
}

bool VidSupport::init(unsigned char* _image, unsigned _width, unsigned _height, int _rotate, unsigned _pitch)
{
	image = _image;
	width = _width;
	height = _height;
	pitch = _pitch;
	rotate = _rotate;
	return true;
}

inline void VidSupport::copyImageIn(unsigned char* dst, unsigned dstPitch, unsigned char* src, unsigned srcPitch,
	unsigned inwidth, unsigned inheight)
{
	// fast, iterative C version
	// copies an width*height array of visible pixels from src to dst
	// srcPitch and dstPitch are the number of garbage bytes after a scanline
	register unsigned lineSize = inwidth << 2;

	while (inheight--) {
		memcpy(dst, src, lineSize);
		src += srcPitch;
		dst += dstPitch;
	}
}

inline void VidSupport::copyImageRotate(unsigned char* ps, unsigned srcPitch, unsigned char* pd, unsigned dstPitch,
	unsigned inwidth, unsigned inheight, int inrotate)
{
	if (!ps || !pd || !inrotate)
		return;

	unsigned char* pss = 0;
	unsigned char* pdd = 0;

	switch (inrotate) {
		case 1: {
			for (int y = 0; y < inheight; y++, pd += dstPitch) {
				pss = ps + (inheight - 1 - y) * 4;
				pdd = pd;
				for (int x = 0; x < inwidth; x++) {
					*(int*)pdd = *(int*)pss;
					pss += srcPitch;
					pdd += 4;
				}
			}
			break;
		}
		case 2: {
			for (int y = 0; y < inheight; y++) {
				pss = ps + y * srcPitch;
				pdd = pd + (inheight - y - 1) * dstPitch + (inwidth - 1) * 4;
				for (int x = 0; x < inwidth; x++) {
					*(int*)pdd = *(int*)pss;
					pss += 4;
					pdd -= 4;
				}
			}
			break;
		}
		case 3: {
			for (int y = 0; y < inheight; y++, pd += dstPitch) {
				pss = ps + y * 4;
				pdd = pd + (inwidth - 1) * 4;
				for (int x = 0; x < inwidth; x++) {
					*(int*)pdd = *(int*)pss;
					pss += srcPitch;
					pdd -= 4;
				}
			}
			break;
		}
	}
}

void VidSupport::copyImage(unsigned char* pd, unsigned dstPitch)
{
	unsigned char* ps = image;

	if (rotate) {
		copyImageRotate(ps, pitch, pd, dstPitch, width, height, rotate);
		return;
	}
	copyImageIn(pd, dstPitch, ps, pitch, width, height);
}

void VidSupport::postCopyImage(unsigned char* pd, unsigned dstPitch)
{
	// do sth.
}

// This function takes a rectangle and scales it to either:
// - The largest possible multiple of both X and Y;
// - The largest possible multiple of Y, modifying X to ensure the correct aspect ratio;
// - The window size
bool VidSupport::scaleImage(void* rect, unsigned gameWidth, unsigned gameHeight)
{
	if (vidFullStretch || !rect || gameWidth == 0 || gameHeight == 0) {
		return 0;
	}

	RECT* rc = (RECT*)rect;
	int width = rc->right - rc->left;
	int height = rc->bottom - rc->top;

	// The multiple of scrnWidth and scrnHeight we can fit in
	int xm = width / gameWidth;
	int ym = height / gameHeight;

	int scrnWidth = systemWorkArea.right - systemWorkArea.left;
	int scrnHeight = systemWorkArea.bottom - systemWorkArea.top;
	if (vidFullscreen) {
		scrnWidth = vidScrnWidth;
		scrnHeight = vidScrnHeight;
	}
	double winAspect = (double)scrnWidth / (double)scrnHeight;

	if (vidCorrectAspect) {					// Correct aspect ratio
		int widthScratch = height * aspect * winAspect / vidScrnAspect;
		if (widthScratch > width) {			// The image is too wide
			if (gameWidth < gameHeight) {	// Vertical games
				height = width * winAspect / (vidScrnAspect * aspect);
			} else {						// Horizontal games
				height = width * vidScrnAspect / (winAspect * aspect);
			}
		} else {
			width = widthScratch;
		}
	} else {
		if (xm && ym) {						// Don't correct aspect ratio
			if (xm > ym) {
				xm = ym;
			} else {
				ym = xm;
			}
			width = gameWidth * xm;
			height = gameHeight * ym;
		} else {
			if (xm) {
				width = gameWidth * xm * height / gameHeight;
			} else {
				if (ym) {
					height = gameHeight * ym * width / gameWidth;
				}
			}
		}
	}

	rc->left = (rc->right + rc->left) / 2;
	rc->left -= width / 2;
	rc->right = rc->left + width;

	rc->top = (rc->top + rc->bottom) / 2;
	rc->top -= height / 2;
	rc->bottom = rc->top + height;

	return 0;
}
